<?php

namespace Modules\Ui\component;

use Closure;
use ErrorException;
use JsonSerializable;

abstract class Component implements JsonSerializable
{

    //组件名称
    protected string $nodeName = 'div';
    //节点熟悉
    protected array $attrs = [];
    //类名
    protected array $class = [];
    //样式
    protected string $style = '';

    //回调方法
    protected ?Closure $callback;


    /**
     * @var string 组件key
     */
    protected string $key = '';


    /**
     * 设置组件节点名称
     * @param string $nodeName
     * @return $this
     */
    public function nodeName(string $nodeName = "div"): Component
    {
        $this->nodeName = $nodeName;
        return $this;
    }

    /**
     * @param array|string $class
     * @return $this
     */
    public function addClass($class = ''): Component
    {
        $this->class = array_unique(array_merge($this->class,is_array($class)?$class:[$class]));
        return $this;
    }

    /**
     * 设置属性样式
     * @param string $style
     * @return $this
     */
    public function style(string $style = ''): Component
    {
        $this->style = $style;
        return $this;
    }

    /**
     * 组件绑定属性
     * @param mixed $data 绑定属性
     * @return $this
     */
    public function data($data): Component
    {
        $this->attrs['data'] = $data;
        return $this;
    }


    /**
     * 设置组件属性
     * @param string $attrName 属性
     * @param mixed $bindValue 值
     * @return $this
     */
    public function attr(string $attrName = '', $bindValue = ''): Component
    {
        $this->attrs[$attrName] = $bindValue;
        return $this;
    }

    /**
     * 设置组件子元素
     * @param mixed $child 子元素
     * @return $this
     */
    public function child($child): Component
    {
        $this->attrs['child'] = $child;
        return $this;
    }

    /**
     * 设置组件子元素
     * @param mixed $child 子元素
     * @return $this
     */
    public function addChild($child): Component
    {
        $this->attrs['child'][] = $child;
        return $this;
    }

    /**
     * 设置组件插槽
     * 'vSlot' => 'options' // 默认插槽
     * @param string $option 插槽参数
     * @return $this
     */
    public function vSlotDefault(string $option = ''): Component
    {
        $this->attrs['vSlot'] = $option;
        return $this;
    }


    /**
     * 设置组件插槽
     * 'vSlot:header' => 'options' // 插槽与插槽参数
     * @param string $slotName 插槽名称
     * @param string $option 插槽参数
     * @return $this
     */
    public function vSlot(string $slotName = '', string $option = ''): Component
    {
        $this->attrs['vSlot:'.$slotName] = $option;
        return $this;
    }

    /**
     * 绑定属性事件指令
     * @param string $bindName
     * @param string $valueName
     * @return $this
     */
    public function vModel(string $bindName, string $valueName = ''): Component
    {

        $this->attrs["vModel:".$bindName] = "this.".($valueName?:$bindName);
        return $this;
    }

    /**
     * 绑定属性事件指令
     * @param string $bindName
     * @param string $valueName
     * @return $this
     */
    public function vBind(string $bindName, string $valueName = ''): Component
    {

        $this->attrs["vBind:".$bindName] = "this.".($valueName?:$bindName);
        return $this;
    }

    /**
     * 点击事件指令
     * '() => { console.log("点了一下~") }'
     * @param string $jsFunction
     * @return $this
     */
    public function click(string $jsFunction = '()=>{}'): Component
    {
        return $this->vOn('click',$jsFunction);
    }

    /**
     * 点击事件指令
     * '() => { console.log("点了一下~") }'
     * @param string $eventName
     * @param string $jsFunction
     * @return $this
     */
    public function vOn(string $eventName = '', string $jsFunction = '()=>{}'): Component
    {
        $this->attrs['vOn:'.$eventName] = $jsFunction;
        return $this;
    }

    /**
     * 判断条件指令
     * @param string|callable $field
     * @param string $condition ['==','===','>','<','>=','<=','!=','!=='] or value
     * @param string $value any string
     * @return $this
     * @throws ErrorException
     */
    public function vIf(string $field = '', string $condition = '', string $value = ''): Component
    {
        if (is_callable($field)){
            $this->attrs['vIf'] = call_user_func($field($this));
        }else{
            $conditions = ['==','===','>','<','>=','<=','!=','!=='];
            if(!$condition){
                throw new ErrorException('缺少 $condition 参数');
            }
            if(in_array($condition,$conditions)){
                $this->attrs['vIf'] = "{$field} {$condition} {$value}";
            }else{
                $this->attrs['vIf'] = "{$field} === {$condition}";
            }
        }
        return $this;
    }

    /**
     * 循环指令
     * @param string $data 循环主体变量
     * @param string $item 循环变量
     * @param string $key 循环索引
     * @return $this
     */
    public function vFor(string $data = 'data',string $item = 'item',string $key = 'key'): Component
    {
        $this->attrs['vFor'] = "({$item}, {$key}) in {$data}";
        return $this;
    }

    public function render(){
        return $this->jsonSerialize();
    }


    public function jsonSerialize()
    {
        $classArr = $this->class;
        if(isset($this->attrs['class'])){
            if(is_array($this->attrs['class'])){
                $classArr = array_merge($classArr,$this->attrs['class']);
            }else{
                $classArr = array_merge($classArr,[$this->attrs['class']]);
            }
        }
        $class = [];
        if($classArr){
            foreach ($classArr as $value){
                $values = is_array($value)?$value:explode(" ",trim($value));
                foreach ($values as $val){
                    $class[] = $val;
                }
            }
        }
        return array_merge([
            'nodeName' => $this->nodeName,
            'class' => array_unique($class),
            'style' => $this->style,
        ],$this->attrs);
    }
}
